package battlezone;

import javax.media.j3d.*;
import javax.vecmath.*;

/**
 * Represents a tank or projectile.
 * Provides functions for getting a Java 3D BranchGroup that is tied to the object's position and azimuth.
 */
public abstract class BattlezoneObject {

    private float _positionX;
    private float _positionY;
    private float _azimuth;
    protected Shape3D _shape;
    protected boolean _isDead = false;
    private BranchGroup _branchGroup = new BranchGroup();
    private TransformGroup _transformGroup = new TransformGroup();
    private Transform3D _transform = new Transform3D();
    private Vector3f _translation = new Vector3f();
    
    protected BattlezoneObject(float positionX, float positionY, float azimuth, Shape3D shape) {
        _positionX = positionX;
        _positionY = positionY;
        _azimuth = azimuth;
        _shape = shape;
        
        //Allow parent to detach this BranchGroup
        _branchGroup.setCapability(BranchGroup.ALLOW_DETACH);
        
        _transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        
        adjustTransform();
        
        _transformGroup.addChild(_shape);
        _branchGroup.addChild(_transformGroup);
    }
    
    /**
     * Makes the transform group match the x, y, and azimuth
     */
    private void adjustTransform() {
        _transform.rotZ(2 * Math.PI - this.getAzimuthInRadians()); //rotZ automatically resets the matrix
        _translation.x = _positionX;
        _translation.y = _positionY;
        _transform.setTranslation(_translation);
        _transformGroup.setTransform(_transform);
    }
    
    public float getPositionX() {
        return _positionX;
    }
    public float getPositionY() {
        return _positionY;
    }
    /**
     * Increments the tank's position.
     * The x and y positions are usually incremented together to avoid jeky movement.
     * @param xBy
     * @param yBy
     */
    public void incrementPosition(float xBy, float yBy) {
        _positionX += xBy;
        _positionY += yBy;
        adjustTransform();
    }
    
    public float getAzimuth() {
        return _azimuth;
    }
    public float getAzimuthInRadians() {
        return (float)Math.toRadians(_azimuth);
    }
    public void incrementAzimuth(float amount) {
        _azimuth += amount;
        normalizeAzimuth();
        adjustTransform();
    }
    
    /**
     * Sets the position and azimuth of the tank at the same time.
     */
    public void setPositionAndAzimuth(float x, float y, float azimuth) {
        _positionX = x;
        _positionY = y;
        _azimuth = azimuth;
        normalizeAzimuth();
        adjustTransform();
    }
    
    /**
     * Converts the azimuth to a value between 0 and 360 degrees.
     */
    private void normalizeAzimuth() {
        if (_azimuth < 0) {
            _azimuth += 360;
        } else if (_azimuth >= 360) {
            _azimuth -= 360;
        }
    }
    
    public BranchGroup getBranchGroup() {
        return _branchGroup;
    }
    
    /**
     * Causes the object to assume a killed state.
     * Called when another object has impacted this object.
     * On tanks, this causes the tank to assume dead-tank geometry.
     * On projectiles, this causes the projectile to dispose itself.
     */
    public abstract void die();
    
    public boolean isDead() {
        return _isDead;
    }
    
    /**
     * Causes the object to throw itself into the garbage, detaching its branch group and doing any other cleanup.
     */
    public void dispose() {
        _branchGroup.detach();
    }
    
    @Override
    public String toString() //for debugging only - will probably be removed in the final release
    {
        return ((Float) _positionX).toString() + ' ' + ((Float) _positionY).toString() + ' ' + ((Float)_azimuth).toString();
    }
}
